
package com.hlkj.pay.app.ad.impl;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import java.math.BigDecimal;
import java.util.UUID;
import java.util.concurrent.Executor;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.hlkj.framework.caches.service.RedisTemplateService;
import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.ad.IAdPayOrderCallService;
import com.hlkj.pay.common.AdResultCode;
import com.hlkj.pay.common.CommonResultCode;
import com.hlkj.pay.common.constants.AdRedisConstant;
import com.hlkj.pay.dto.ad.gateway.Tuia;
import com.hlkj.pay.enums.AdEnum;
import com.hlkj.pay.enums.CommonEnum;
import com.hlkj.pay.gateway.ad.IAdOrderGateway;
import com.hlkj.pay.infrastructure.model.ad.AdInfoConfigDO;
import com.hlkj.pay.infrastructure.model.ad.AdInfoDO;
import com.hlkj.pay.infrastructure.model.ad.AdPayOrderDO;
import com.hlkj.pay.service.ad.IAdInfoService;
import com.hlkj.pay.service.ad.IAdPayOrderService;
import com.hlkj.pay.util.MerchantUtils;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2024/10/24 18:09
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AdPayOrderCallServiceImpl implements IAdPayOrderCallService {

    private final IAdInfoService adInfoService;

    private final RedisTemplateService redisTemplateService;

    private final IAdPayOrderService adPayOrderService;

    private final AdPayOrderMessageHandler adPayOrderMessageHandler;

    private final IAdOrderGateway adOrderGateway;

    @Value("${hlkj.pay.adCall:false}")
    private boolean adCall;

    @Override
    public void processCallMessage(AdPayOrderDO adPayOrderDO) {
        Long adId = adPayOrderDO.getAdId();
        log.info("收到回传消息处理 adId:{},mchOrderNo:{}", adId, adPayOrderDO.getMchOrderNo());
        AdInfoConfigDO adInfoConfigDO = adInfoService.queryConfigByAdId(adId);
        Object payOrder = redisTemplateService.get(AdRedisConstant.AD_PAY_ORDER_COUNT + adId);
        if (payOrder == null || "0".equals(payOrder.toString())) {
            log.info("回传参数错误 广告id对应的支付订单数为 0 adId:{}", adId);
            // AdPayOrderQueryDto adPayOrderQueryDto = new AdPayOrderQueryDto();
            // adPayOrderQueryDto.setAdId(adId);
            // adPayOrderQueryDto.setState(PayOrderEnums.PAY_ORDER_STATUS.SUCCESS.getCode());
            return;
            // Long count = adPayOrderService.queryCount(adPayOrderQueryDto);
            // redisTemplateService.set(AdRedisConstant.AD_PAY_ORDER_COUNT + adId, 1);
            // payOrder = 1;
        }
        Long payOrderCount = Long.valueOf(payOrder.toString());
        if (payOrderCount <= 0) {
            log.info("收到回传消息处理,支付订单数量为0 不处理 adId:{}", adId);
            return;
        }
        Object callOrder = redisTemplateService.get(AdRedisConstant.AD_CALL_ORDER_COUNT + adId);
        Long callOrderCount = 0L;
        if (callOrder != null) {
            callOrderCount = Long.valueOf(callOrder.toString());
        }
        // 计算是否满足扣率
        BigDecimal callRate = adInfoConfigDO.getCallRate();
        // 目标回传率
        BigDecimal targetCallRate = MerchantUtils.divide(MerchantUtils.subtract(new BigDecimal(100), callRate), new BigDecimal(100));
        // 实际回传率
        BigDecimal reCallRate = MerchantUtils.divide(new BigDecimal(callOrderCount), new BigDecimal(payOrderCount));
        // 比较当前的扣率与设置的扣率
        log.info("广告id:{},对应的目标回传率为 targetCallRate:{},对应的实际回传率为 reCallRate:{}", adId, MerchantUtils.bigDecimalToString(targetCallRate),
                MerchantUtils.bigDecimalToString(reCallRate));
        // 实际回传小于目标回传
        if (reCallRate.compareTo(targetCallRate) < 0) {
            // 需要回传的订单数量
            int needCallOrderCount = targetCallRate.subtract(reCallRate).multiply(new BigDecimal(payOrderCount)).intValue();
            if (needCallOrderCount > 0) {
                try {
                    log.info("需要回传订单数 adId:{}, 实际只回传 pageSize:{} needCallOrderCount:{}", adId, 1, needCallOrderCount);
                    processTuia(adPayOrderDO, adInfoConfigDO, true);
                }
                catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
            else {
                log.info("当前需要回传订单数为0 无需回传 adId:{}", adId);
            }
        }
        else {
            log.info("当前实际回传率 不小于目标回传率,广告id:{},对应的目标回传率为 targetCallRate:{},对应的实际回传率为 reCallRate:{}", adId, MerchantUtils.bigDecimalToString(targetCallRate),
                    MerchantUtils.bigDecimalToString(reCallRate));
        }
    }

    @Override
    public CommonResult<Void> callBackOrder(String mchOrderNo) {
        log.info("callBackOrder mchOrderNo:{}", mchOrderNo);
        try {
            AdPayOrderDO payOrderDO = adPayOrderService.queryDetailCache(mchOrderNo);
            if (payOrderDO == null) {
                return CommonResult.error(AdResultCode.PAY_ORDER_NOT_EXITS);
            }
            if (CommonEnum.YES_NO_TYPE.YES.getCode().equals(payOrderDO.getCallStatus())) {
                return CommonResult.error(AdResultCode.PAY_ORDER_HAS_CALL);
            }
            if (!StringUtils.hasText(payOrderDO.getTuiId())) {
                return CommonResult.error(AdResultCode.REFUND_APPLY_ORDER_AID_NOT_EXIST);
            }
            // if (!adCall && (new BigDecimal(1).compareTo(payOrderDO.getPayAmount()) > 0))
            // {
            // return CommonResult.success();
            // }
            AdInfoConfigDO adInfoConfigDO = adInfoService.queryConfigByAdId(payOrderDO.getAdId());
            log.info("手动回传订单数 adId:{}", payOrderDO.getAdId());
            processTuia(payOrderDO, adInfoConfigDO, false);
            return CommonResult.success();
        }
        catch (Exception e) {
            log.error("callBackOrder error:{}", e.getMessage(),e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public void resetCallRate(Long adId) {
        log.info("回传率重置 adId:{}", adId);
        redisTemplateService.set(AdRedisConstant.AD_PAY_ORDER_COUNT + adId, 0);
        redisTemplateService.set(AdRedisConstant.AD_CALL_ORDER_COUNT + adId, 0);
    }

    void processTuia(AdPayOrderDO payOrderDO, AdInfoConfigDO adInfoConfigDO, boolean system) {
        try {
            AdInfoDO adInfoDO = adInfoService.queryById(adInfoConfigDO.getAdId());

            Tuia tuia = adOrderGateway.syncCallBack(adInfoConfigDO,adInfoDO.getMediaId(), payOrderDO.getTuiId());
            log.info("推啊回传 返回参数 params:{}", JsonUtils.toJsonString(tuia));
            if ("0000000".equals(tuia.getRecord())) {
                // 同步订单回传状态
                adPayOrderService.updateCallOrderAll(payOrderDO.getId(), tuia.getA_oId());
                if (system) {
                    String callOrderCountKey = AdRedisConstant.AD_CALL_ORDER_COUNT + payOrderDO.getAdId();
                    redisTemplateService.incr(callOrderCountKey, 1);
                }
                // 发送消息
                adPayOrderMessageHandler.sendAdStatistics(payOrderDO.getAdId(), UUID.randomUUID().toString(), new BigDecimal(1), AdEnum.STATISTICS_TYPE.CALL_ORDER,
                        payOrderDO.getCreateTime());
            }
        }
        catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Bean(name = "adOrderCallTaskExecutor")
    public Executor adOrderCallTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2); // 核心线程数
        executor.setMaxPoolSize(5); // 最大线程数
        executor.setQueueCapacity(100); // 队列容量
        executor.setKeepAliveSeconds(60); // 线程空闲时间
        executor.setThreadNamePrefix("Async-orderCall-"); // 线程名称前缀
        executor.initialize();
        return executor;
    }
}
